/**
 * 
 */
package name.marz.to.go.ahg.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import name.marz.to.go.ahg.core.Parameters;
import name.marz.to.go.ahg.core.exception.InvalidDocumentException;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.FormElement;
import org.jsoup.select.Elements;

/**
 * @author m.goto
 *
 */
public final class HttpUtil {
	public static final String getCharset(String content_type_value) {
		String[] s = content_type_value.split(";");
		Pattern ptn = Pattern.compile("charset=");
		for ( int i=0; i<s.length; i++ ) {
			Matcher m = ptn.matcher(s[i]);
			boolean found = m.find();
			if ( found ) {
				return m.replaceAll("").trim();
			}
		}
		return null;
	}
	public static final String getCharset(Header content_type_header) {
		String v = content_type_header.getValue();
		if ( v != null ) return getCharset(v);
		return null;
	}
	public static final String getCharset(HttpResponse resp) {
		Header h = resp.getFirstHeader("Content-Type");
		if ( h != null ) return getCharset(h);
		return null;
	}
	public static final String getCharset(Document doc) {
		Element e = doc.getElementsByAttributeValue("http-equiv","content-type").first();
		if ( e == null ) return null;
		String content_type_value = e.attr("content");
		if ( content_type_value != null ) return getCharset(content_type_value);
		return null;
	}
	public static URI createURISafety(String host, String path) {
		URI uri = null;
		try {
			uri = new URI(host+path);
		} catch (URISyntaxException e) {
			throw new IllegalArgumentException("Illegal URI "+host+path,e);
		}
		return uri;
		
	}
	public static URI createURISafety(String str) {
		URI uri = null;
		try {
			uri = new URI(str);
		} catch (URISyntaxException e) {
			throw new IllegalArgumentException("Illegal URI "+str,e);
		}
		return uri;
		
	}
	public static URI createURISafety(String scheme,String authority, String path,String query) {
		URI uri = null;
		try {
			uri = new URI(scheme,authority,path,query,null);
		} catch (URISyntaxException e) {
			throw new IllegalArgumentException("Illegal URI : scheme="+scheme+" authority="+authority+" path="+path,e);
		}
		return uri;
	}

	public static URI createURISafety(String scheme,String authority, String pathAndQuery) {
		URI uri = null;
		try {
			URL url = new URL(scheme,authority,pathAndQuery);
			uri = url.toURI();
		} catch (MalformedURLException e) {
			throw new IllegalArgumentException("Illegal URL : scheme="+scheme+" authority="+authority+" path="+pathAndQuery,e);
		} catch (URISyntaxException e) {
			throw new IllegalArgumentException("Illegal URI : scheme="+scheme+" authority="+authority+" path="+pathAndQuery,e);
		}
		return uri;
	}
	
	/**
	 * cookieを保存する
	 * @param file 保存先のファイル
	 * @param store 保存したいCookieStoreオブジェクト
	 * @throws IOException
	 */
	public static void saveCookie(CookieStore store,File file) throws IOException {
		FileOutputStream fos = new FileOutputStream(file);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		try {
			oos.writeObject(store.getCookies());
			LogUtil.log(Level.FINE,store.getCookies(),"saved cookies");
		} finally {
			oos.close();
		}
	}
	/**
	 * cookieをファイルから読み込む
	 * 
	 * @param file cookieを保存したファイル
	 * @param store 読み出したいCookieStoreオブジェクト このインスタンスに読み込んだCookieがaddされます
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static void loadCookie(File file,CookieStore store) throws IOException, ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
		@SuppressWarnings("unchecked")
		List<Cookie> cs = (List<Cookie>)ois.readObject();
		LogUtil.log(Level.FINE,cs,"readed cookies");
		
		for ( Cookie c : cs ) {
			store.addCookie(c);
		}
		ois.close();
	}
	
	public static String getFormActionString(Document doc,String name) {
		Elements forms = doc.getElementsByTag("form");
		if ( forms == null ) throw new InvalidDocumentException("Can't find FORM tags", doc);
		StringBuffer namebuf = new StringBuffer("[name=");
		namebuf.append(name).append("]");
		Elements form = forms.select(namebuf.toString());
		if ( form == null ) throw new InvalidDocumentException("Can't find "+namebuf.toString(), doc);
				
		return form.first().attr("action");
	}
	public static final Parameters getParametersFromFormTag(Document doc,String formName) {
		Elements forms = doc.getElementsByTag("form");
		if ( forms.size() == 0 ) throw new IllegalArgumentException("Can't find FORM tags");
		
		for (Element form : forms) {
			if (form.attr("name").equals(formName) ) {
				Parameters p = new Parameters();
				p.putAll(getParametersFromInputTags(form));
				p.putAll(getParametersFromSelectTags(form));
				return p;
			}
		}
		throw new IllegalArgumentException("Can't find FORM tag \""+formName+"\"");
	}
	public static final Parameters getParametersFromFormTag(FormElement form) {
		Parameters p = new Parameters();
		p.putAll(getParametersFromInputTags(form));
		p.putAll(getParametersFromSelectTags(form));
		return p;
	}
	public static final Parameters getParametersFromInputTags(Element elem) {
		Elements inputs = elem.getElementsByTag("input");
		return getParametersFromInputTags(inputs);
	}
	public static final Parameters getParametersFromSelectTags(Element elem) {
		Elements selects = elem.getElementsByTag("select");
		return getParametersFromSelectTags(selects);
	}
	public static final Parameters getParametersFromInputTags(Elements inputTags) {
		Parameters p = new Parameters();
		for ( Element input : inputTags ) {
			if ( input.attr("name").length() == 0 ) continue;
			p.put(input.attr("name"), input.attr("value"));
		}
		return p;
	}
	public static final Parameters getParametersFromSelectTags(Elements selectTags) {
		Parameters p = new Parameters();
		for ( Element select : selectTags ) {
			if ( select.attr("name").length() == 0 ) continue;
			Elements options = select.getElementsByTag("option");
			String value = null;
			if ( options.size() == 1) {
				value = options.first().attr("value");
			} else {
				for (Element option : options) {
					if ( option.hasAttr("selected") ) {
						value = option.attr("value");
						break;
					}
				}
			}
			p.put(select.attr("name"), value);
		}
		return p;
		
	}
	public static final Parameters getParametersFromInputTags(Document doc) {
		Elements inputs = doc.getElementsByTag("input");
		return getParametersFromInputTags(inputs);
	}
	public static final Parameters getParametersFromSelectTags(Document doc) {
		Elements selects = doc.getElementsByTag("select");
		return getParametersFromSelectTags(selects);
	}
}
